#include <algorithm>
#include <exception>
#include <memory>
#include <odb/database.hxx>
#include <odb/mysql/connection-factory.hxx>
#include <odb/mysql/database.hxx>
#include "student.hxx"
#include "student-odb.hxx"
#include <gflags/gflags.h>
#include <odb/query.hxx>
#include <odb/result.hxx>
#include <odb/transaction.hxx>

DEFINE_string(host, "127.0.0.1", "mysql服务器地址");
DEFINE_int32(port, 0, "mysql服务器端口");
DEFINE_string(db, "TestDB", "默认数据库名称");
DEFINE_string(user, "root", "mysql用户名");
DEFINE_string(pswd, "weng9244", "mysql密码");
DEFINE_string(cset, "utf8", "mysql客户端字符集");
DEFINE_int32(max_pool, 3, "mysql连接池最大连接数量");


void insert_classes(odb::mysql::database& db)
{
    try {
        // 开始事务 - 相当于 start transaction
        odb::transaction trans(db.begin());
        Classes c1("101");
        Classes c2("201");
        // 插入数据 
        db.persist(c1);
        db.persist(c2);
        trans.commit();
    } catch (const std::exception& e) {
        std::cout << "插入班级数据出错: " << e.what() << '\n';
    }
}

void insert_student(odb::mysql::database& db)
{
    try {
        // 获取事务对象开启事务
        odb::transaction trans(db.begin());
        Student s1(1, "张三", 18, 1);
        Student s2(2, "李四", 19, 1);
        Student s3(3, "王五", 18, 1);
        Student s4(4, "赵六", 15, 2);
        Student s5(5, "刘七", 18, 2);
        Student s6(6, "孙八", 23, 2);
        db.persist(s1);
        db.persist(s2);
        db.persist(s3);
        db.persist(s4);
        db.persist(s5);
        db.persist(s6);
        trans.commit();
    } catch (const std::exception& e) {
        std::cout << "插入学生数据出错: " << e.what() << '\n';
    }
}

void update_student(odb::mysql::database& db, Student& stu)
{
    try {
        odb::transaction trans(db.begin());
        db.update(stu);
        trans.commit();
    } catch (const std::exception& e) {
        std::cout << "更新学生数据出错: " << e.what() << '\n';
    }
}

Student select_student(odb::mysql::database& db)
{
    Student res;
    try {
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<Student> result;
        result ret(db.query<Student>(query::name == "张三"));
        if(ret.size() != 1) {
            std::cout << "查询结果异常, 无法更新数据!\n";
            return Student();
        }
        res = *ret.begin();
        trans.commit();
    } catch (const std::exception& e) {
        std::cout << "查询学生数据出错: " << e.what() << '\n';
    }
    return res;
}

void remove_student(odb::mysql::database& db)
{
    try {
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        db.erase_query<Student>(query::classes_id == 2);
        trans.commit();
    } catch (std::exception &e) {
        std::cout << "删除学生数据出错: " << e.what() << '\n';
    }
}

void classes_student(odb::mysql::database& db)
{
    try {
        odb::transaction trans(db.begin());
        typedef odb::query<struct classes_student> query;
        typedef odb::result<struct classes_student> result;
        result ret(db.query<struct classes_student>(query::classes::id == 2));
        for(auto it = ret.begin(); it != ret.end(); ++it) {
            std::cout << it->id << '\n';
            std::cout << it->sn << '\n';
            std::cout << it->name << '\n';
            std::cout << *it->age << '\n';
            std::cout << it->classes_name << '\n';
        }
        trans.commit();
    } catch (std::exception &e) {
        std::cout << "多表查询数据出错: " << e.what() << '\n';
    }
}

void all_student(odb::mysql::database& db)
{
    try {
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<struct all_name> result;
        result ret(db.query<struct all_name>());
        for(auto it = ret.begin(); it != ret.end(); ++it) {
            std::cout <<  it->name << '\n';
        }
        trans.commit();
    } catch (std::exception &e) {
        std::cout << "全查询数据出错: " << e.what() << '\n';
    }
}

int main(int argc, char *argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, true);

    // 1. 构造连接池工厂配置对象
    std::unique_ptr<odb::mysql::connection_pool_factory> cpf = 
        std::make_unique<odb::mysql::connection_pool_factory>(FLAGS_max_pool, 0);
    
    // 2. 构造数据库操作对象
    odb::mysql::database db(FLAGS_user, FLAGS_pswd, FLAGS_db, 
        FLAGS_host, FLAGS_port, "", FLAGS_cset, 0, std::move(cpf));

    // 3. 数据操作
    // 3-1 插入数据
    // insert_classes(db);
    // insert_student(db);

    // 3-2 更新数据
    // auto stu = select_student(db);
    // std::cout << stu.sn() << '\n';
    // std::cout << stu.name() << '\n';
    // if(stu.age()) std::cout << *stu.age() << '\n';
    // std::cout << stu.classes_id() << '\n';
    // stu.age(88);
    // update_student(db, stu);

    // 3-4 删除数据
    // remove_student(db);

    // 3-5 多表查询
    // classes_student(db);

    // 3-6 全查询
    all_student(db);

    return 0;
}